Chinaunix首页 | 论坛 | 博客
  • 博客访问: 271812
  • 博文数量: 95
  • 博客积分: 2047
  • 博客等级: 大尉
  • 技术积分: 1022
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-14 16:18
文章分类

全部博文(95)

文章存档

2013年(1)

2011年(94)

我的朋友

分类: LINUX

2011-08-13 16:56:39

搞了个很潮的标题~RT73遇上S1R72V17Ralink公司的RT73芯片平台是造就了不少优秀的54M无线网卡,它的Linux驱动做的也很完善,我在S3C2410NXP ISP1160上都能够正常使用。但是,当RT73碰上了EPSONS1R72V17(以后简称V17)这颗USB-HOST芯片,却无法正常工作。表面现象为可以正确加载驱动,但一旦使用ifconfig激活无线网卡后,RT73进程很快就会占据100%CPU资源,造成系统假死。我自己调试了一段时间,至少可以肯定不是RT73驱动程序的问题,但是没有完全解决问题。正好这天EPSON的工程师来南京,带来了USB协议分析仪等高级货,和他一起调了一整天终于解决了这个问题。记录一下整个调试过程:

首先打开RT73的调试信息,将V171160进行对比,因为我以前调试过,里面有错误信息。

**RT2573**<7>Submit Rx URB failed -19

V17的输出信息里面多了这么一条语句,无线网卡传输的灯不会闪,自然也连接不上Dlink无线路由器。发送URB失败,在ruusb_bulk.c中发现其源码:

if((ret = rtusb_submit_urb(pUrb))!=0)

       {

              DBGPRINT(RT_DEBUG_ERROR,"Submit Rx URB failed %d\n", ret);

              return;

       }

说明rtusb_submit_urb函数返回了-19这个错误,而且是USB在进行bulk传输时出现了问题。查阅相关资料发现上面这个函数会调用到Linux内核中的drivers/usb/core/urb.c中的usb_submit_urb(struct urb *urb, gfp_t mem_flags)函数。-19的含义是-ENODEV,在usb_submit_urb函数中只能是这个发送前的判断了:

if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)

       return -ENODEV;

将判断中的值打印出来,发现错误出现在dev->state这个状态上。此时RT73要进行bulk传输,但是只有dev->state= USB_STATE_CONFIGURED时才可以使用USBEndpoint0之外的端口(EP0只能进行控制传输),查看state发现是USB_STATE_ADDRESS,所以函数返回错误。

和工程师讨论了一下,感觉USB控制器在配置后就应该处于USB_STATE_CONFIGURED状态了,这儿还是处于USB_STATE_ADDRESS很奇怪。增加了更多的调试信息后发现在插上无线网卡后USB的状态的确已经处于Configured态,但是启动网卡后又改变回Address。于是我们开始跟踪V17的代码,看是什么时候将状态改回去的。发现在s1r72xxx-q.c文件中的check_device_request函数能够改变USB的状态。激活无线网卡时运行了如下代码导致无法USB状态变化:

case USB_REQ_SET_CONFIGURATION:

switch (urb->dev->state) {

/** * - 1.2.3. USB_STATE_CONFIGURED:            */

              case USB_STATE_CONFIGURED:

                            if (urb->setup_packet[2] == 0

                                   && urb->setup_packet[3] == 0) {

                                   urb->dev->state = USB_STATE_ADDRESS;

                            }

                            break;

              default:

                            break;

              }

       这儿用了发送USB_REQ_SET_CONFIGURATION的附加信息(setup_packet[23])进行判断,估计和RT73附带信息不兼容,导致USB状态机又跳回Address了。我们查看了以他USB控制器的代码,基本没有发现有在驱动里面改变USB状态的,V17的驱动这儿写的蛮奇怪,也可能是日本人写程序更严谨吧,还在意状态机的变化。

       以上算是第一个问题,解决方法就是将urb->dev->state = USB_STATE_ADDRESS;这句话给注释掉,以后再也跳不回Address啦。我之前调试差不多就做到这一步,当然我没有修改V17的代码,我在urb.c里面那个出错判断用了以下语句将USB状态机强行置为configured态,当然效果是一样的。

       usb_set_device_state(dev, USB_STATE_CONFIGURED);           

       OK,第一阶段完成,运行后不会有URB错误了,但是还是不能正常工作。于是我们继续跟踪代码,又回到了RT73网卡的驱动调试信息,这次竟然能够发现Dlink路由器了,但是又出现了新的错误信息。

       **RT2573**<7>SYNC - Switch to channel 6, SSID dlink

**RT2573**<7>SYNC - Wait BEACON from 00:21:91:6f:f1:f2 ...

**RT2573**<7>SYNC - receive desired BEACON at JoinWaitBeacon... Channel = 6

**RT2573**<7>SYNC - after JOIN, SupRateLen=4, ExtRateLen=8

**RT2573**<7>AUTH - Send AUTH request seq#1 (Alg=0)  6...

**RT2573**<7><---MlmeRate 1     Channel 6

**RT2573**<7>AUTH - AuthTimeout

**RT2573**<7>AUTH – AuthTimeoutAction

发现路由器,但是连接超时。更关键的错误是这儿:

**RT2573**<7>Bulk Out MLME Failed

bulk发送MLME数据错误?就是说bulk传输还是存在问题。EPSON工程师使用USB分析器观察数据,的确是只有bulk in的数据包,没有bulk out的包,所以能够搜索到无线网卡,但是不能进行下一步通讯。这段调试信息的出处还是rtusb_bulk.c这个文件。在RTUSBBulkOutMLMEPacketComplete函数中有如下代码:

       if ((!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS)) &&

                     (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS)) &&

                     (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) &&

                     (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET)))

              {

                     DBGPRINT_RAW(RT_DEBUG_ERROR, "Bulk Out MLME Failed\n");

                     RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_BULKOUT_RESET);

                     RTUSBEnqueueInternalCmd(pAd, RT_OID_USB_RESET_BULK_OUT);

              }

       虽然是RTUSBBulkOutMLMEPacketComplete函数报错,但这个函数是bulk调用完成才执行的,真正调用发送urb的函数应该是RTUSBBulkOutMLMEPacket()。

       // Init Tx context descriptor

       RTUSBInitTxDesc(pAd, pMLMEContext, 0, RTUSBBulkOutMLMEPacketComplete);

       这段代码是填充USBbulk数据结构体,并把发送完成的调用函数勾上去,既然能够发送完成,说明下面的rtusb_submit_urb(pUrb)函数至少运行完了,但是返回的数据不正确,还是没有能够正确发送。

       rtusb_submit_urb(pUrb)调用了urb.c中的usb_submit_urb(),在usb_submit_urb()最后的return op->submit_urb (urb, mem_flags);才是真正的发送函数。这个函数的真身是什么呢?在hcd.c中有如下内容:

* usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)

 */

static struct usb_operations usb_hcd_operations = {

       .get_frame_number =   hcd_get_frame_number,

       .submit_urb =              hcd_submit_urb,

       .unlink_urb =       hcd_unlink_urb,

       .buffer_alloc =             hcd_buffer_alloc,

       .buffer_free =        hcd_buffer_free,

       .disable =              hcd_endpoint_disable,

};

       .submit_urb =              hcd_submit_urb,看到这行吧,下面来找hcd_submit_urb()函数,其中的最后       status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);

说明调用了urb_enqueue (hcd, ep, urb, mem_flags);函数这又是何方神圣V17的驱动s1r72xxx-hcd.c函数注册结构体如下

static struct hc_driver s1r72xxx_hc_driver = {

       .description           = DRV_NAME,

       .hcd_priv_size              = sizeof(struct hcd_priv),

       .irq                = s1r72xxx_hcd_irq,

       .flags                    = HCD_USB2 | HCD_MEMORY,

       .reset                    = s1r72xxx_hcd_reset,

       .start                    = s1r72xxx_hcd_start,

       .suspend        = s1r72xxx_hcd_suspend,

       .resume                = s1r72xxx_hcd_resume,

       .stop                     = s1r72xxx_hcd_stop,

       .get_frame_number      = s1r72xxx_hcd_get_frame,

       .urb_enqueue        = s1r72xxx_hcd_enqueue,

       .urb_dequeue        = s1r72xxx_hcd_dequeue,

       .endpoint_disable  = s1r72xxx_hcd_endpoint_disable,

       .hub_status_data   = s1r72xxx_hcd_hub_status,

       .hub_control         = s1r72xxx_hcd_hub_control,

       .bus_suspend        = s1r72xxx_hcd_hub_suspend, //kyon

       .bus_resume         = s1r72xxx_hcd_hub_resume,

       .start_port_reset    = s1r72xxx_start_port_reset,

};

其中就有.urb_enqueue              = s1r72xxx_hcd_enqueue,肯定会调用到这个函数。在这个函数中加入调试信息,发现发送错误的时候,函数没有运行完毕就直接返回了,主要问题在如下函数处:

/**

        * - 3. Allocate CH:

        *  - Check allocated CH to a same EP. If allocated CH is not exist,

        *    allocate new CH.:

        */

       dev_addr = get_devaddr(urb);

       allocated = get_ch_connected_to(priv, dev_addr, ep);

       //allocated      = -19;

       ch          = allocated;

 

       DPRINT(DBG_API,"%s: get ch connected %d\n",__FUNCTION__, allocated);

       s1r72xxx_queue_log(S_R_DEBUG_QUEUE, allocated, hcd_queue->count);

       s1r72xxx_queue_log(S_R_DEBUG_QUEUE, urb->transfer_buffer_length

              ,urb->actual_length);

 

       if (allocated < 0){

              /* if this ep is not asigned early enqueue, allocate new CH. */

              ch = alloc_ch_resource(hcd, priv, dev_addr, ep, urb);

              DPRINT(DBG_API,"%s: alloc ch resource %d\n",__FUNCTION__,ch);

             

       }

这一段主要是分配用来传输USB数据的endpoint。调试时我们发现了一段很有趣的事情,系统首先会调用get_ch_connected_to(priv, dev_addr, ep);试图寻找一个已有的endping,如果找不到就调用alloc_ch_resource(hcd, priv, dev_addr, ep, urb);分配一个。结果正确传输的数据包在get_ch_connected_to(priv, dev_addr, ep);函数的返回都是找不到,必要要重新分配一个,偏偏我们传输错误的bulk包,在get_ch_connected_to()时获得了ep1,没有执行alloc_ch_resource()函数。

问题的关键就是这儿!因为此时要bulk out ,此时获得了ed1,但是ep1已经被bulk in给占用了!v17bulk inbulk out的通常做法是用两个ednpoint来完成,此时bulk in已经占用了ep1,而bulk out时却分配了ep1,当然发送不出去。据epson工程师分析,应该是get_ch_connected_to()获取ep信息时没有判断bulk的状态是in还是out,于是我们在get_ch_connected_to()函数中添加的相关通讯方向的判断:

if ((((ep->desc.bEndpointAddress) & USB_ENDPOINT_DIR_MASK)

              == USB_DIR_IN && priv->ch_info[ch_ct].dir == S_R_CH_DIR_IN)

              && (((ep->desc.bEndpointAddress) & USB_ENDPOINT_DIR_MASK)

              == USB_DIR_OUT && priv->ch_info[ch_ct].dir == S_R_CH_DIR_OUT) 

{                                

              DPRINT(DBG_API,"%s:match CH%d addr=%d, ep=%d\n", __FUNCTION__,

                            ch_ct, dev_addr, ep_no);

              return ch_ct;

}

好了,当再次bulk out调用get_ch_connected_to()时,由于bulk方向不同,不会被分配到ep1去了,而是从新申请了ep2通道。

至此,华硕无线网卡上的小蓝灯终于开始闪烁,S1R72V17不怕RT73

最后要感谢EPSON公司的钟先生陪我调到晚上10点,辛苦了。

阅读(1149) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~