dm9k_probe函数的全部代码如下
int __init dm9k_probe(struct net_device *dev, unsigned long addr) { struct board_info *db; /* Point a board information structure */ u32 id_val; u16 i, j; int retval; /* Search for DM9000 serial NIC */ PUTB(DM9KS_VID_L, addr); id_val = GETB(addr + 2); /* Change offset to 2 ^^^^^ */ PUTB(DM9KS_VID_H, addr); id_val |= GETB(addr + 2) << 8; PUTB(DM9KS_PID_L, addr); id_val |= GETB(addr + 2) << 16; PUTB(DM9KS_PID_H, addr); id_val |= GETB(addr + 2) << 24; if (id_val != DM9KS_ID && id_val != DM9010_ID) { /* Dm9k chip not found */ printk("dmfe_probe(): DM9000 not found. ID=%08X\n", id_val); return -ENODEV; } printk(" I/O: %lx, VID: %x \n",addr, id_val); /* Allocated board information structure */ memset(dev->priv, 0, sizeof(struct board_info)); db = (board_info_t *)dev->priv; dmfe_dev = dev; db->io_addr = addr; db->io_data = addr + 2; /* Change offset to 2 ^^^^^ */ /* driver system function */ dev->base_addr = addr; dev->irq = IRQ_EINT2; dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; dev->watchdog_timeo = HZ; dev->tx_timeout = dmfe_timeout; dev->stop = &dmfe_stop; dev->get_stats = &dmfe_get_stats; dev->set_multicast_list = &dm9000_hash_table; dev->do_ioctl = &dmfe_do_ioctl; for(i=0,j=0x10; i<6; i++,j++) { db->srom[i] = ior(db, j); } /* Set Node Address */ for (i=0; i<6; i++) dev->dev_addr[i] = db->srom[i]; retval = register_netdev(dev); if (retval == 0) { /* now, print out the card info, in a short format.. */ printk("%s: at %#lx IRQ %d\n", dev->name, dev->base_addr, dev->irq); if (dev->dma != (unsigned char)-1) printk(" DMA %d\n", dev->dma); if (!is_valid_ether_addr(dev->dev_addr)) { printk("%s: Invalid ethernet MAC address. Please " "set using ifconfig\n", dev->name); } else { /* Print the Ethernet address */ printk("%s: Ethernet addr: ", dev->name); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x\n", dev->dev_addr[5]); } } return 0; }
|
函数首先调用PUTB来写dm9000a芯片,来看看PUTB的实现
#define PUTB(d,a) *((volatile unsigned char *) (a)) = d
|
可见,PUTB是直接使用的指针,而没有使用内核提供的write等函数,同样,GETB函数如下
#define GETB(a) *((volatile unsigned char *) (a))
|
注意,这里的地址都是虚拟地址,因为前面调用函数dm9k_probe时传递的addr时重新映射后的,而不是直接传送的物理地址。
具体操作涉及到dm9000a的硬件实现,做简单的说明。dm9000a有两个PORT,一个是INDEX PORT,另一个就是DATA PORT。具体访问哪一个是根据CMD引脚的信号来确定的:CMD为0,则访问INDEX,否则,访问DATA。访问寄存器之前,必须将寄存器的地址存放在INDEX PORT。
首先,驱动程序需要读芯片的ID。DM9000A的ID存放在四个不同的字节中,分别叫做Vendor ID和Product ID。将着四个字节读出来,组合后应该得到0x90000A46,如果读出来的ID与该值不相等,说明不是DM9000A网卡,程序将返回,初始化失败。
读出ID相同后,就可以认为系统中存在dm9000a网卡了,接下来就开始进行其他初始化工作。主要工作
dev->base_addr = addr; dev->irq = IRQ_EINT2; dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; dev->watchdog_timeo = HZ; dev->tx_timeout = dmfe_timeout; dev->stop = &dmfe_stop; dev->get_stats = &dmfe_get_stats; dev->set_multicast_list = &dm9000_hash_table; dev->do_ioctl = &dmfe_do_ioctl;
|
就是为net_device的成员指定功能函数,以便系统需要的时候进行调用。完成这些基本的工作后,就可以向系统注册设备了
retval = register_netdev(dev);
|
注册完成,该函数就返回。probe函数剩下的就是对返回值的判断了,若注册成功,直接推出,probe完成;失败的话,还需要将ioremap过的地方ioumap掉,request_mem_region的地方release掉。
-----------------------------To be continued 2008-8-1
由于篇幅限制,下面的部分见:
http://blog.chinaunix.net/u1/57747/showart_1100944.html
阅读(1702) | 评论(0) | 转发(1) |