为什么Linux USB驱动程序通过线路传输异常值

时间:2012-08-27 07:13:18

标签: c linux usb driver

我试图通过处理源代码并将其与使用usbmon收集的USB I / O十六进制转储相关联来了解USB Wi-Fi卡的Linux驱动程序。它一直都很顺利,但只有一个字节在数千个类似于它的内容中似乎与源代码无关。具体来说,它是Line 726中的/drivers/staging/rtl8187se/r8180_rtl8225z2.c(在Linux内核源目录中),其内容为:

write_phy_ofdm(dev, 0x02, 0x62); mdelay(1);

我希望这一行能产生4次USB写操作,即第三次写入有效载荷为0x62。相反,usbmon报告的在线路上传输的第三个写入有效负载为0x42(不是0x62)。为了说明,此处是usbmon针对此特定调用的输出(每隔一行的最后一列是四个有效负载0x000x000x42,{{1} }):

0x82

以下是相关的功能定义:

/drivers/staging/rtl8187se/r8180_core.c

ffff88011d317600 2404077138 S Co:2:004:0 s 40 05 ff7f 0000 0001 1 = 00
ffff88011d317600 2404077255 C Co:2:004:0 0 1 >
ffff88008d9a0600 2404077263 S Co:2:004:0 s 40 05 ff7e 0000 0001 1 = 00
ffff88008d9a0600 2404077380 C Co:2:004:0 0 1 >
ffff88011d317000 2404077388 S Co:2:004:0 s 40 05 ff7d 0000 0001 1 = 42
ffff88011d317000 2404077505 C Co:2:004:0 0 1 >
ffff88008d9a09c0 2404077513 S Co:2:004:0 s 40 05 ff7c 0000 0001 1 = 82  

inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data)
{
    data = data & 0xff;
    rtl8185_write_phy(dev, adr, data);
}

void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data) {  

    u32 phyw;

    adr |= 0x80;

    phyw = ((data<<8) | adr);

    /* Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. */
    write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24));
    write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16));     
    write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8));  
    write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff)));

    /* this is ok to fail when we write AGC table. check for AGC table might
    be   * done by masking with 0x7f instead 
    of 0xff      */     /* if (phyr != (data&0xff)) 
    DMESGW("Phy write timeout %x %x %x", phyr, data, adr); */ 
}

/arch/xtensa/include/asm/io.h

void write_nic_byte(struct net_device *dev, int x, u8 y)
{
    writeb(y, (u8 *)dev->mem_start + x);
    udelay(20);
}

通过调用订单,我们从#define writeb(b, addr) (void)((*(volatile unsigned char *)(addr)) = (b)) 开始。 write_phy_ofdm(dev, 0x02, 0x62);write_phy_ofdm()的{​​{1}}行data,但data = data & 0xff只占用较低的字节,因此此时不会更改0x62。因此,datawrite_phy_ofdm作为0x62参数传递给datartl8185_write_phy()rtl8185_write_phydata打包到u32的低16位,行adr。请注意,phyw = ((data << 8) | adr);仅向上移动8位,因为data仅占用较低的8位,因此它们不会修改adr的数据部分。前两个phyw调用分别将write_nic_byte()的最高和第二高位字节写入地址phyw0xff7f。由于0xff7e的两个最高阶字节未被占用,因此这些有效载荷为phyw,如预期的那样。 第三次0x00电话让我感到悲痛。我希望它只是简单地将数据write_nic_byte()移位回最低位字节并传输0x62。为什么传播0x62是我逃避的原因。

我必须承认,我对低级0x42电话的理解很明显,也许这就是意外发生的事情。我能找到的任何线索的唯一香味都在diff from 2009中,其中包含以下行:writeb()(注意值write_phy_ofdm(dev, 0x02, ((priv->card_type == USB) ? 0x42 : 0x62)); mdelay(1);饲养其丑陋的头部)。我应该注意到,我甚至重新编译了内核驱动程序,并将其添加到运行的内核0x42 / rmmod rtl8187中,以确保我的源代码与正在运行的驱动程序一致(不是更新或更旧) ),但我仍然得到insmod /path/to/my/compiled/.ko/file而不是0x42

任何人都可以建议我可能出错的地方吗?我完全没有想法。

1 个答案:

答案 0 :(得分:1)

事实证明,我甚至没有找到正确的函数定义,因为在不同的文件中有两个名为rtl8225z2_rf_init()的函数。一个在/drivers/staging/rtl8187se/r8180_rtl8225z2.c(我正在查看的版本中没有被执行)和另一个在/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c中(我正在查看的正确版本,正在执行) 。他们只是略有不同,但一个使用write_phy_ofdm(dev, 0x02, 0x62);而另一个使用write_phy_ofdm(dev, 0x02, 0x42);。这里的教训是,不要依赖于使用Emacs中的标签导航到函数定义。