2410平台上dm9000a网卡驱动分析.docx

上传人:b****4 文档编号:24650176 上传时间:2023-05-29 格式:DOCX 页数:21 大小:30.75KB
下载 相关 举报
2410平台上dm9000a网卡驱动分析.docx_第1页
第1页 / 共21页
2410平台上dm9000a网卡驱动分析.docx_第2页
第2页 / 共21页
2410平台上dm9000a网卡驱动分析.docx_第3页
第3页 / 共21页
2410平台上dm9000a网卡驱动分析.docx_第4页
第4页 / 共21页
2410平台上dm9000a网卡驱动分析.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

2410平台上dm9000a网卡驱动分析.docx

《2410平台上dm9000a网卡驱动分析.docx》由会员分享,可在线阅读,更多相关《2410平台上dm9000a网卡驱动分析.docx(21页珍藏版)》请在冰豆网上搜索。

2410平台上dm9000a网卡驱动分析.docx

2410平台上dm9000a网卡驱动分析

2410平台上dm9000a网卡驱动分析

   该驱动基于linux-2.6.24.4内核。

 

   首先,需要在arch/arm/mach-s3c2410/mach-smdk2410.c文件中添加如下代码:

staticstructresources3c_dm9000_resource[]={

   [0]={

       .start=0x10000000,

       .end=0x10000040,

       .flags=IORESOURCE_MEM

   },

   [1]={

       .start=IRQ_EINT2,

       .end=IRQ_EINT2,

       .flags=IORESOURCE_IRQ,

   }

};

注意上面的start、end等地址是指的网卡的物理地址。

然后,还要在该文件中加入如下代码:

struct platform_devices3c_device_dm9000={

   .name="dm9000",

   .id=-1,

   .num_resources=ARRAY_SIZE(s3c_dm9000_resource),

   .resource=s3c_dm9000_resource,

};

需要特别注意上面的name字段,当设备驱动程序寻找设别资源时,会根据该字段对设备进行匹配。

另外,该文件中的smdk2410_devices[]数组中,还需要加入s3c_device_dm9000,不然系统启动时没有找到该资源就不会调用相应的probe函数。

   下面分析驱动程序的probe函数。

若驱动被编译进内核,则在系统启动的时候,该函数会被调用。

该函数的源代码如下:

static int dm9k_drv_probe(struct platform_device *pdev)

{

        struct net_device *ndev;

        unsigned long base;

        unsigned int *addr = NULL;

        int ret = -ENODEV;

        ndev = alloc_etherdev(sizeof(struct board_info));

        if (!

ndev) {

                printk("%s:

couldnotallocatedevice.\n", CARDNAME);

                return -ENOMEM;

        }

        

        ndev->dma = (unsigned char)-1;

        if (pdev->num_resources < 2 || pdev->num_resources > 3) {

                printk("DM9000:

Wrongnumofresources%d\n", pdev->num_resources);

                ret = -ENODEV;

                goto out;

        }

        base = pdev->resource[0].start;

        ndev->irq = pdev->resource[1].start;

        /*

         *Requesttheregions.

         */

        if (!

request_mem_region(base, 4, ndev->name)) {

                ret = -EBUSY;

                goto out;

        }

        addr = ioremap(base, 4);

        if (!

addr) {

                ret = -ENOMEM;

                goto release_mem;

        }

        ret = dm9k_probe(ndev, (unsigned long)addr);

        if (ret !

= 0) {

         iounmap(addr);

 release_mem:

                release_mem_region(base, 4);

 out:

                printk("%s:

notfound(%d).\n", CARDNAME, ret);

                kfree(ndev);

        }

        return ret;

}

函数首先调用alloc_etherdev,该函数在include/linux/etherdevice.h中声明,其中有如下语句:

#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)

而alloc_etherdev_mq函数又定义在net/ethernet/eth.c中,如下:

struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)

{

    return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count);

}

可见,该函数只是用自己的参数来调用alloc_netdev_mq函数。

alloc_netdev_mq函数定义在net/core/dev.c中,原型如下:

struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,

        void (*setup)(struct net_device *), unsigned int queue_count)

关于该函数的说明:

/**

 * alloc_netdev_mq-allocatenetworkdevice

 * @sizeof_priv:

 sizeofprivatedatatoallocatespacefor

 * @name:

  devicenameformatstring

 * @setup:

  callbacktoinitializedevice

 * @queue_count:

 thenumberofsubqueuestoallocate

 *

 * Allocatesastructnet_devicewithprivatedataareafordriveruse

 * andperformsbasicinitialization. Alsoallocatessubquuestructs

 * foreachqueueonthedeviceattheendofthenetdevice.

 */

可见,alloc_etherdev为设备驱动分配了私有数据空间,并对设备驱动做了一些初始化工作。

 

接下来,设备驱动将要检查设备的resources的数量,如果数量小于2或者大于3,则初始化函数自动返回,初始化失败。

我们的设备驱动中,resources的数量为2:

一个表示设备的IO地址,另一个是设备的中断号。

 

代码

       base = pdev->resource[0].start;

        ndev->irq = pdev->resource[1].start;

分别得到设备的端口地址和中断号。

接下来,驱动程序将向系统申请io内存,从地址base开始,大小为4个字节。

如果申请成功,接下来需要做的就是将地址重新映射,从地址base开始,长度为4个字节。

这样做的原因主要是驱动程序一般不直接访问物理地址,而访问虚拟地址。

地址重新映射成功后,就调用dm9k_probe函数进行设备初始化。

dm9k_probe函数的全部代码如下

int __initdm9k_probe(struct net_device *dev, unsigned long addr)

{

        struct board_info *db; /*Pointaboardinformationstructure*/

        u32id_val;

        u16i, j;

        int retval;

          /*SearchforDM9000serialNIC*/

        PUTB(DM9KS_VID_L, addr);

        id_val = GETB(addr + 2); /*Changeoffsetto2^^^^^*/

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

                /*Dm9kchipnotfound*/

                printk("dmfe_probe():

DM9000notfound.ID=%08X\n", id_val);

                return -ENODEV;

                }

                

        printk("I/O:

%lx,VID:

%x\n",addr, id_val);

        /*Allocatedboardinformationstructure*/

        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; /*Changeoffsetto2^^^^^*/

        /*driversystemfunction*/

                                

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

               

          }

       

        /*SetNodeAddress*/

        for (i=0; i<6; i++)

                dev->dev_addr[i] = db->srom[i];

        retval = register_netdev(dev);

        if (retval == 0) {

                /*now,printoutthecardinfo,inashortformat..*/

                printk("%s:

at%#lxIRQ%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:

InvalidethernetMACaddress.Please"

                               "setusingifconfig\n", dev->name);

                } else {

                        /*PrinttheEthernetaddress*/

                        printk("%s:

Ethernetaddr:

", 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,一个是INDEXPORT,另一个就是DATAPORT。

具体访问哪一个是根据CMD引脚的信号来确定的:

CMD为0,则访问INDEX,否则,访问DATA。

访问寄存器之前,必须将寄存器的地址存放在INDEXPORT。

首先,驱动程序需要读芯片的ID。

DM9000A的ID存放在四个不同的字节中,分别叫做VendorID和ProductID。

将着四个字节读出来,组合后应该得到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掉。

前面分析了dm9000a网卡的probe部分,接下来继续其他部分。

 

当用户在命令行下使用ifconfig等命令的时候,网卡设备将打开,系统将调用open函数。

dm9000a的open函数如下

static int dmfe_open(struct net_device *dev)

{

        board_info_t *db = (board_info_t *)dev->priv;

        u8reg_nsr;

        int i;

       

        if (request_irq(dev->irq,&dmfe_interrupt,IRQF_SHARED,dev->name,dev)) 

                return -EAGAIN;

        /*GrabtheIRQ*/

       set_irq_type(dev->irq, IRQ_TYPE_EDGE_RISING);

        /*InitilizeDM910Xboard*/

        dmfe_init_dm9000(dev);

 

        /*Initdrivervariable*/

        db->reset_counter = 0;

        db->reset_tx_timeout = 0;

        db->cont_rx_pkt_cnt = 0;

        

        /*checklinkstateandmediaspeed*/

        db->Speed =10;

        i=0;

        do {

                reg_nsr = ior(db,0x1);

                if(reg_nsr & 0x40) /*linkOK!

!

*/

                {

                        /*waitfordetectedSpeed*/

                        mdelay(200);

                        reg_nsr = ior(db,0x1);

                        if(reg_nsr & 0x80)

                                db->Speed =10;

                        else

                                db->Speed =100;

                        break;

                }

                i++;

                mdelay

(1);

        }while(i<3000); /*wait3second*/

        //printk("i=%dSpeed=%d\n",i,db->Speed); 

        /*setandactiveatimerprocess*/

        init_timer(&db->timer);

        db->timer.expires = DMFE_TIMER_WUT * 2;

        db->timer.data = (unsigned long)dev;

        db->timer.function = &dmfe_timer;

        add_timer(&db->timer); //MovetoDM9000initiallizationwasfinished.

         

        netif_start_queue(dev);

        return 0;

}

函数首先向系统申请中断,利用内核提供的request_irq函数。

该函数声明于include/linux/interrupt.h中,而它的定于位于kernel/irq/manage.c中。

关于它的说明和原型如下

/**

 *    request_irq-allocateaninterruptline

 *    @irq:

Interruptlinetoallocate

 *    @handler:

FunctiontobecalledwhentheIRQoccurs

 *    @irqflags:

Interrupttypeflags

 *    @devname:

Anasciinamefortheclaimingdevice

 *    @dev_id:

Acookiepassedbacktothehandlerfunction

 *

 *    Thiscallallocatesinterruptresourcesandenablesthe

 *    interruptlineandIRQhandling.Fromthepointthis

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 材料科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1