我正试图通过处理源代码并将其与使用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写入,即第三个写入负载是a0x62。相反,由usbmon报告的第三个写有效载荷在导线上传输时是0x42(不是0x62)。为了说明,这里是这个特定调用的usbmon输出(每第二行的最后一列是四个有效负载0x000x000x420x82):
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

相关功能定义如下:
/驱动程序/staging/rtl8187se/r8180_core.c
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); */
}


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

/arch/xtensa/include/asm/io.h目录
#define writeb(b, addr) (void)((*(volatile unsigned char *)(addr)) = (b))

通过调用顺序,我们从write_phy_ofdm(dev, 0x02, 0x62);开始。write_phy_ofdm()位掩码data与行data = data & 0xff在一起,但是0x62只占用较低的字节,因此此时不会更改data。因此write_phy_ofdm0x62作为data参数传递给rtl8185_write_phy()rtl8185_write_phydata行将adrphyw = ((data << 8) | adr);压缩到u32的下16位。注意,data只会向上移动8位,因为adr只占用较低的8位,或者使用它们不会修改phyw的数据部分。前两个write_nic_byte()调用分别将phyw的最高和第二高位字节写入地址0xff7f0xff7e。由于phyw的两个最高阶字节未占用,这将导致0x00的两个有效负载。第三个电话让我伤心。我希望它只是将数据位移回到最低阶字节,然后发送。我不明白它为什么要传送。
我必须承认,我对低级别write_nic_byte()调用的理解很模糊,也许这就是发生意外的地方。我能找到的线索中唯一的气味是在一个diff from 2009中,它包含一行:0x62(注意抬起它丑陋的头的值)。我应该注意到,我甚至重新编译了内核驱动程序,并使用0x62/0x42将其添加到正在运行的内核中,以确保我拥有的源代码与正在运行的驱动程序一致(不是更新的或更旧的),但我仍然得到writeb()而不是write_phy_ofdm(dev, 0x02, ((priv->card_type == USB) ? 0x42 : 0x62)); mdelay(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中导航到带有标记的函数定义。

关于c - 为什么Linux USB驱动程序通过网络传输异常值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12137651/

10-10 06:30