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( "<DM9KS> 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掉。