0

I am trying to understand a Linux driver for a USB Wi-Fi card by working through the source code and correlating it against a USB I/O hex dump collected using usbmon. It's been going quite well but there is just one byte amongst thousands similar to it that seems to not correlate back to the source code. Specifically, it is Line 726 in /drivers/staging/rtl8187se/r8180_rtl8225z2.c (inside the Linux kernel source directory), which reads:

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

I expect this line to result in 4 USB writes, namely with the third write payload being a 0x62. Instead, the third write payload as reported by usbmon as being transmitted on the wire is0x42 (not 0x62). To illustrate, here is the output from usbmon for this specific call (last column of every second line are the four payloads 0x00, 0x00, 0x42, 0x82):

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  

And below are the relevant function definitions:

/drivers/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);
}

and

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); */ 
}

and

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))

Running through the call order, we start with write_phy_ofdm(dev, 0x02, 0x62);. write_phy_ofdm() bitmasks data with the line data = data & 0xff, but 0x62 only occupies the lower byte anyway, so this doesn't change data at this point. So write_phy_ofdm passes 0x62 onwards as the data argument to rtl8185_write_phy(). rtl8185_write_phy packs data and adr into the lower 16 bits of a u32 with the line phyw = ((data << 8) | adr);. Note that data just shifts up 8-bits and because adr only occupies the lower 8-bits, OR'ing them doesn't modify the data portion of phyw. The first two write_nic_byte() calls write the highest and second highest order bytes of phyw out to addresses 0xff7f and 0xff7e respectively. Because the two highest order bytes of phyw are unoccupied, these result in two payloads of 0x00 as expected. The third write_nic_byte() call is the one giving me grief. I expect it to be simply bitshifting the data 0x62 back down to the lowest order byte and transmitting 0x62. Why it is transmitting 0x42 is what escapes me.

I must admit my understanding of the low level writeb() calls is merky, and perhaps this is where something unexpected is happening. The only scent of any clue at all I could find is in a diff from 2009 which contains the line: write_phy_ofdm(dev, 0x02, ((priv->card_type == USB) ? 0x42 : 0x62)); mdelay(1); (note the value 0x42 rearing its ugly head). I should note that I've even recompiled the kernel driver and added it into the running kernel with rmmod rtl8187/insmod /path/to/my/compiled/.ko/file just to be sure the source I had was consistent with the running driver (not newer or older), but I still get 0x42 instead of 0x62.

Can anyone suggest where I might be going wrong? I'm all out of ideas.

4

1 回答 1

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 中导航到带有标签的函数定义。

于 2012-08-28T07:35:07.327 回答