/* if they give us an odd I/O address, then do ONE write to
the address port, to get it back to address zero, where we
expect to find the EISA signature word. An IO with a base of 0x3
will skip the test for the ADD_PORT. */
//下面这段代码比较费解,不是说代码的意思不好解释,而是为什么只在寄地址
//才检查呢?根据数据手册的说明“The CS8900A reads 3000h from IObase+0Ah after
//the reset, until the software writes a non-zero value at IObase+0Ah. The
//3000h value can be used as part of the CS8900A signature when the system
//scans for the CS8900A.”从这段话可知,这只能作为扫描到cd8900存在部分的依据;
//从后面的代码中可以看到,还需要确定cs8900的ID号后才能真正确保cs8900存在。
if (ioaddr & 1) {
if (net_debug > 1)
printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
if ((ioaddr & 2) != 2)
if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) {
printk(KERN_ERR "%s: bad signature 0x%x\n",
dev->name, readword(ioaddr & ~3, ADD_PORT));
retval = -ENODEV;
goto out2;
}
}
/* Fill in the 'dev' fields. */
dev->base_addr = ioaddr;
/* get the chip type */
rev_type = readreg(dev, PRODUCT_ID_ADD);//rev_type=0x0a00,这个值是实际
//测试出来的,但根据cs8900A的数据手册,该值应该是0x0700。???
lp->chip_type = rev_type &~ REVISON_BITS;
lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
//执行上面赋值后lp->chip_type=0x0,lp->chip_revision=0x4b。注意这里的加法运算
//rev_type & REVISON_BITS)>>8=0x0a,这个0x0a是数字,'A'转换成十
//六进制后为0x41,所以,0x41+0x0a=0x4b,0x4b在ascii码中对应的字母为'K'
/* Check the chip type and revision in order to set the correct send command
CS8920 revision C and CS8900 revision F can use the faster send. */
lp->send_cmd = TX_AFTER_381; //默认每次传输381字节,
//根据数据手册可以传输的字节
//选项有5、381、1021、all四个,但这里的驱动不支持1021字节的选项。
if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')//此条件满足
lp->send_cmd = TX_NOW;//选择每次传输5字节
if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
lp->send_cmd = TX_NOW;
if (net_debug && version_printed++ == 0)
printk(version);
printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ",
dev->name,
lp->chip_type==CS8900?'0':'2',
lp->chip_type==CS8920M?"M":"",
lp->chip_revision,
dev->base_addr);//按照上面的分析,这里打印的应该形如:
//cs89x0.c: v2.4.3-pre1 Russell Nelson ,
//Andrew Morton eth0: cs8900 rev K found at 0xf4000300
reset_chip(dev); //重新复位cs8900a
/* Here we read the current configuration of the chip. If there
is no Extended EEPROM then the idea is to not disturb the chip
configuration, it should have been correctly setup by automatic
EEPROM read on reset. So, if the chip says it read the EEPROM
the driver will always do *something* instead of complain that
adapter_cnf is 0. */
......
//以下代码一直到printk(KERN_INFO "cs89x0 media %s%s%s",功能为
//从EEPROM中读出配置信息,并填充dev结构的相关域。
if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
(EEPROM_OK|EEPROM_PRESENT)) {//读取SelfST寄存器,并判断EEPROM
//是否存在若存在,则判断是否读取操作成功。上述条件满足,
//则读出EEPROM中的配置信息填充dev相关域。
/* Load the MAC. */
for (i=0; i 读取以太网地址
unsigned int Addr;
Addr = readreg(dev, PP_IA+i*2);
dev->dev_addr[i*2] = Addr & 0xFF;
dev->dev_addr[i*2+1] = Addr >> 8;
}
/* Load the Adapter Configuration.
Note: Barring any more specific information from some
other source (ie EEPROM+Schematics), we would not know
how to operate a 10Base2 interface on the AUI port.
However, since we do read the status of HCB1 and use
settings that always result in calls to control_dc_dc(dev,0)
a BNC interface should work if the enable pin
(dc/dc converter) is on HCB1. It will be called AUI
however. */
lp->adapter_cnf = 0;
i = readreg(dev, PP_LineCTL); //读取LineCTL寄存器,
//确定MAC配置和物理接口
/* Preserve the setting of the HCB1 pin. */
if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL))
lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
/* Save the sqelch bit */
if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
/* Check if the card is in 10Base-t only mode */
if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T;
/* Check if the card is in AUI only mode */
if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI;
/* Check if the card is in Auto mode. */
if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
if (net_debug > 1)
printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
dev->name, i, lp->adapter_cnf);
/* IRQ. Other chips already probe, see below. */
if (lp->chip_type == CS8900)
lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
printk( "[Cirrus EEPROM] ");
}
printk("\n");
/* First check to see if an EEPROM is attached. */
......//以下检查EEPROM的相关信息
if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)//是否EEPROM存在
printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff)
//读取RRPROM失败
printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n");
} else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff)
/* Check if the chip was able to read its own configuration starting
at 0 in the EEPROM*/
if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
(EEPROM_OK|EEPROM_PRESENT))
printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
} else {
/* This reads an extended EEPROM that is not documented
in the CS8900 datasheet. 扩展配置*/
/* get transmission control word but keep the autonegotiation bits */
if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
/* Store adapter configuration */
if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2];
/* Store ISA configuration */
lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2];
dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2]
/* eeprom_buff has 32-bit ints, so we can't just memcpy it */
/* store the initial memory base address */
for (i = 0; i
dev->dev_addr[i*2] = eeprom_buff;
dev->dev_addr[i*2+1] = eeprom_buff >> 8;
}
if (net_debug > 1)
printk(KERN_DEBUG "%s: new adapter_cnf: 0x%x\n",
dev->name, lp->adapter_cnf);
}
/* allow them to force multiple transceivers. If they force multiple, autosense */
{
int count = 0;
if (lp->force & FORCE_RJ45) {lp->adapter_cnf |= A_CNF_10B_T; count++; }
if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_AUI; count++; }
if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_10B_2; count++; }
if (count > 1) {lp->adapter_cnf |= A_CNF_MEDIA_AUTO; }
else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; }
else if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_MEDIA_AUI; }
else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; }
}
if (net_debug > 1)
printk(KERN_DEBUG "%s: after force 0x%x, adapter_cnf=0x%x\n",
dev->name, lp->force, lp->adapter_cnf);
/* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
/* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
/* FIXME: we don't set the Ethernet address on the command line. Use
ifconfig IFACE hw ether AABBCCDDEEFF */
/* If this is a CS8900 then no pnp soft */
if (lp->chip_type != CS8900 &&
/* Check if the ISA IRQ has been set */
(i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
(i != 0 && i 非cs8900芯片
if (!dev->irq)
dev->irq = i;
} else {
i = lp->isa_config & INT_NO_MASK;//由于没有EEPROM,所以lp->isa_config=0
if (lp->chip_type == CS8900) {
/* Translate the IRQ using the IRQ mapping table. */
if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
//sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])求cs8900_irq_map数据元个数
printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
else
i = cs8900_irq_map;//i保存了中断号
lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
} else {
int irq_map_buff[IRQ_MAP_LEN/2];
if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
IRQ_MAP_LEN/2,
irq_map_buff) >= 0) {
if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1]
}
}
if (!dev->irq)
dev->irq = i;//填充dev->irq,按照前面的定义该值为53
}
1.9 一些问题总结
这里没有讲解cs8900驱动的移植过程,需要移植的朋友可以参见前面提到的weibing的博客文章。这里需要补充的是很多朋友在移植成功了以后,发现内核会打印出如下的消息:
cs89x0_probe1() successful
cs89x0:cs89x0_probe(0x0)
cs8900a: request_region(0xf4000300, 0x10) failed
cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP
该消息的很奇怪,先是说cs89x0_peobe1成功,后面又提示说失败,而且没有影响网络驱动的功能,这时为什么呢?回忆在net_olddevs_init函数时,它调用了8次ethif_probe2函数,也就是说cs89x0_peobe1不被调用了一次,第一次成功了,后面的肯定会失败,如果按照这种思路,那应该会打印7次失败信息,而这里只有一次,不解ing!这个问题也可以简单的解决,我采用了下面的方法解决此问题,判断cs89x0_probe的参数是否大于0,如果大于0就直接退出,这使得cs89x0_probe函数只正常执行一次,这样处理以后就没有提示失败的信息。
To be continuing……
------ anmnmnlly
------ 2007.11.30