所以函数中的第一语句获取的是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";