Chinaunix首页 | 论坛 | 博客
  • 博客访问: 517407
  • 博文数量: 87
  • 博客积分: 4086
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 15:55
文章分类

全部博文(87)

文章存档

2012年(3)

2010年(13)

2009年(7)

2008年(64)

我的朋友

分类: LINUX

2008-08-01 15:57:04

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

阅读(1668) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~