DM9000网卡驱动详细分析(2)

所以函数中的第一语句获取的是mini2440_dm9k_pdata结构中的内容,它只初始化了一个成员,另外的指针成员并没有初始化.平台设备的资源在struct resource mini2440_dm9k_resource[]中定义,有地址IO,数据IO以及中断号.

 

struct board_info *db; /* Point a board information structure */

这个结构体是私有数据结构体,表征的是DM9000网卡的所有相关信息.当建立完数据结构之间的关系后,要想获取DM9000网卡的信息,就从此结构中读取.其定义为:

 

/* Structure/enum declaration ------------------------------- */

typedef struct board_info {

 

void __iomem *io_addr; /* Register I/O base address */ //地址IO

void __iomem *io_data; /* Data I/O address */ //数据IO

u16 irq; /* IRQ */ //中断

 

u16 tx_pkt_cnt; //表征DM9000网卡中TX SRAM中的待发送数据包个数

u16 queue_pkt_len;

u16 queue_start_addr;

u16 queue_ip_summed;

u16 dbug_cnt;

u8 io_mode; /* 0:word, 2:byte */

u8 phy_addr;

u8 imr_all;

 

unsigned int flags;

unsigned int in_suspend :1;

int debug_level;

 

enum dm9000_type type; //网卡类型

 

void (*inblk)(void __iomem *port, void *data, int length); //这三个函数指针与struct dm9000_plat_data中的三个成员一样,以后将

void (*outblk)(void __iomem *port, void *data, int length); //用于对DM9000网卡的数据的读写操作,在后面会根据情况进行初始化

void (*dumpblk)(void __iomem *port, int length);

 

struct device *dev;     /* parent device */

 

struct resource *addr_res;   /* resources found */ //这几个资源的指针用于后面的相关资源申请,注册

struct resource *data_res;

struct resource *addr_req;   /* resources requested */

struct resource *data_req;

struct resource *irq_res;

 

struct mutex addr_lock; /* phy and eeprom access lock */

 

struct delayed_work phy_poll;

struct net_device  *ndev;

 

spinlock_t lock;

 

struct mii_if_info mii;

u32 msg_enable;

 

int rx_csum;

int can_csum;

int ip_summed;

} board_info_t;

 

接着往下看dm9000_probe函数:

/* Init network device */

ndev = alloc_etherdev(sizeof(struct board_info));

分配一个网络设备结构体.struct net_device是网卡驱动中最核心的一个结构,连接了上层网络协议栈和底层的设备驱动,其结构比较庞大,在此不贴出来了.相关的成员在分析的时候会讲到.这里的分配函数的参数却是私有数据结构体的大小,为什么呢?其实这是老方法了.在分配net_device结构的时候,不仅仅分配net_device结构,还将分配其私有数据结构,和网络队列.最终的分配函数见driver/net/core/dev.c文件alloc_netdev_mq()函数.SET_NETDEV_DEV(ndev, &pdev->dev); //将ndev中的dev成员的parent设置为pdev中的dev成员(指向同一结构)

/* setup board info structure */

db = netdev_priv(ndev); //将ndev与私有数据结构联系起来,以后就可以直接通过ndev找到db结构了

 

db->dev = &pdev->dev;

db->ndev = ndev; //通过db也可以找到ndev结构

至此,数据结构之间的关系已经构建起来了.下面要做的是申请并注册资源.

 

db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

获取DM9000网卡的资源.

 

申请并映射O地址资源:

db->addr_req = request_mem_region(db->addr_res->start, iosize,pdev->name);

db->io_addr = ioremap(db->addr_res->start, iosize);

 

申请并映射IO数据资源:

db->data_req = request_mem_region(db->data_res->start, iosize,pdev->name);

db->io_data = ioremap(db->data_res->start, iosize);

 

//将申请到的资源记录到net_device结构当中

ndev->base_addr = (unsigned long)db->io_addr; //首地址

ndev->irq = db->irq_res->start; //中断号

 

/* ensure at least we have a default set of IO routines */

dm9000_set_io(db, iosize); //设置IO的数据位,这里是default值,下面会根据具体的情况再进行改变

 

if (pdata != NULL) {

/* check to see if the driver wants to over-ride the

* default IO width */

 

if (pdata->flags & DM9000_PLATF_8BITONLY)

dm9000_set_io(db, 1);

 

if (pdata->flags & DM9000_PLATF_16BITONLY) // 根据前面的static struct dm9000_plat_data mini2440_dm9k_pdata = {

// .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),

// }; 得来的

dm9000_set_io(db, 2);

 

if (pdata->flags & DM9000_PLATF_32BITONLY)

dm9000_set_io(db, 4);

 

/* check to see if there are any IO routine

* over-rides */

 

if (pdata->inblk != NULL)

db->inblk = pdata->inblk;

 

if (pdata->outblk != NULL)

db->outblk = pdata->outblk;

 

if (pdata->dumpblk != NULL)

db->dumpblk = pdata->dumpblk;

 

db->flags = pdata->flags;

}

 

#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL

db->flags |= DM9000_PLATF_SIMPLE_PHY;

#endif

 

dm9000_set_io()函数实现如下:

 

static void dm9000_set_io(struct board_info *db, int byte_width)

{

/* use the size of the data resource to work out what IO

* routines we want to use

*/

 

switch (byte_width) {

case 1:

db->dumpblk = dm9000_dumpblk_8bit;

db->outblk  = dm9000_outblk_8bit;

db->inblk   = dm9000_inblk_8bit;

break;

 

 

case 3:

dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit/n");

case 2:

db->dumpblk = dm9000_dumpblk_16bit; //什么都不做

db->outblk  = dm9000_outblk_16bit; //用于将struct sk_buff 结构中的数据写入到TX SRAM中的写操作函数

db->inblk   = dm9000_inblk_16bit; //用于将接收到的RX SRAM中的数据读到struct sk_buff结构中的读操作函数,具体代码见下:

break;

 

case 4:

default:

db->dumpblk = dm9000_dumpblk_32bit;

db->outblk  = dm9000_outblk_32bit;

db->inblk   = dm9000_inblk_32bit;

break;

}

}

 

//在发送和接受数据时起到重要作用的读写函数:

 

static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count)

{

writesw(reg, data, (count+1) >> 1);

}

 

static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)

{

readsw(reg, data, (count+1) >> 1);

}

 

//继续往下:

dm9000_reset(db); //网卡的复位,实现如下:

 

static void dm9000_reset(board_info_t * db)

{

dev_dbg(db->dev, "resetting device/n");

 

/* RESET device */

writeb(DM9000_NCR, db->io_addr);

udelay(200);

writeb(NCR_RST, db->io_data);

udelay(200);

}

从这个函数可以看出DM9000网卡的读写方法:先将要读写的寄存器的地址写入到io_addr地址(地址IO)中,然后将要写入的数据写入到io_data地址(数据IO)中.

 

/* try multiple times, DM9000 sometimes gets the read wrong */

for (i = 0; i < 8; i++) {

id_val  = ior(db, DM9000_VIDL);

id_val |= (u32)ior(db, DM9000_VIDH) << 8;

id_val |= (u32)ior(db, DM9000_PIDL) << 16;

id_val |= (u32)ior(db, DM9000_PIDH) << 24;

 

if (id_val == DM9000_ID)

break;

dev_err(db->dev, "read wrong id 0x%08x/n", id_val);

}

id_val = ior(db, DM9000_CHIPR);

 

以上读取DM9000网卡的ID号,并将值写入DM9000_CHIPR寄存器中.然后就是设置网卡类型.

 

ether_setup(ndev);

 

ndev->netdev_ops = &dm9000_netdev_ops; //重要的结构,下面会有分析

ndev->watchdog_timeo = msecs_to_jiffies(watchdog);

ndev->ethtool_ops = &dm9000_ethtool_ops;

/*struct net_device中的ethtool_ops成员也是一个结构体,其中基本上都是函数指针,主要实现一些辅助的功能,如网卡的相关信息获取,可变参数的设置等.*/

 

db->msg_enable       = NETIF_MSG_LINK;

db->mii.phy_id_mask  = 0x1f;

db->mii.reg_num_mask = 0x1f;

db->mii.force_media  = 0;

db->mii.full_duplex  = 0;

db->mii.dev     = ndev;

db->mii.mdio_read    = dm9000_phy_read;

db->mii.mdio_write   = dm9000_phy_write;

 

mac_src = "eeprom";

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值