分析内核自带的dm9000网卡驱动程序:
static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
},
.probe = dm9000_probe,
.remove = dm9000_drv_remove,
.suspend = dm9000_drv_suspend,
.resume = dm9000_drv_resume,
};
1 从驱动的入口函数开始分析
dm9000_init
>platform_driver_register(&dm9000_driver)//这里注册了个平台driver驱动
===>>linux-2.6.22\arch\arm\plat-s3c24xx\devs.c
/*加入DM9000网卡支持*/
#include <linux/dm9000.h>
#include <linux/ioport.h>
#define DM9000_BASE 0x20000000
static struct resource s3c_dm9000_resource[] ={
[0] = {
.start = DM9000_BASE,
.end = DM9000_BASE +0x03 ,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DM9000_BASE + 0x4,
.end = DM9000_BASE + 0x4 +0x3 ,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
static struct dm9000_plat_data s3c_device_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY,
};
struct platform_device s3c_device_dm9000 = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_dm9000_resource),
.resource = s3c_dm9000_resource,
.dev ={
.platform_data = &s3c_device_dm9000_platdata,
}
};
===>>EXPORT_SYMBOL(s3c_device_dm9000);
那么接下来就分析平台driver的probe函数。
>dm9000_probe
>配置网卡所使用的内存bank相关的memory controller:bwscon、bankcon4、s3c2410_gpio_cfgpin
>struct net_device *ndev = alloc_etherdev //分配一个网卡结构体
> 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);
> request_mem_region//为相关结构体成员映射内存空间
> dm9000_set_io(db, 2);
db->outblk = dm9000_outblk_16bit;
> dm9000_reset(db)
> ether_setup(ndev);//设置net_device一些通用的成员
> ndev->open = &dm9000_open;
ndev->hard_start_xmit = &dm9000_start_xmit; //最重要的函数:用于发包
ndev->tx_timeout = &dm9000_timeout;
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
ndev->stop = &dm9000_stop;
ndev->get_stats = &dm9000_get_stats;
ndev->set_multicast_list = &dm9000_hash_table;
> is_valid_ether_addr(ndev->dev_addr) //检测是否是有效的mac地址,如果无效可以手动地写入MAC地址
> platform_set_drvdata(pdev, ndev);
> ret = register_netdev(ndev);//注册网卡
2 接下来分析网卡的open函数 dm9000_open
dm9000_open
> request_irq(dev->irq, &dm9000_interrupt, IRQF_SHARED, dev->name, dev)//注册中断
> dm9000_reset
> dm9000_init_dm9000(dev)
> init_timer(&db->timer);。。。。。等操作
加入一个定时器,定时2秒,
处理函数:dm9000_timer
>mii_check_media(&db->mii, netif_msg_link(db), 0);
> mii_check_media(&db->mii, netif_msg_link(db), 1);//检查mii接口的duplex 改变
> netif_start_queue(dev);//启动网卡数据队列
3 接下来分析网卡的发包函数dm9000_start_xmit (ndev->hard_start_xmit = &dm9000_start_xmit)
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)//发包函数
> netif_stop_queue(dev);
> iow(db, DM9000_IMR, IMR_PAR);/* Disable all interrupts */
writeb(DM9000_MWCMD, db->io_addr); /* Move data to DM9000 TX RAM */
> (db->outblk)(db->io_data, skb->data, skb->len)
||
>也就是调用: dm9000_outblk_16bit(db->io_data, skb->data, skb->len) //拷贝skb->data中数据到网卡数据io
>writesw(db->io_data, skb->data, (skb->len+1) >> 1);
> 第一次发包?立即发:进行入队列-》db->tx_pkt_cnt++; db->queue_pkt_len = skb->len;
> dev_kfree_skb(skb);
> netif_wake_queue
> iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);/* Re-enable interrupt */
4 收包分析
当有数据包时,引发中断,调用中断注册的处理函数dm9000_interrupt
dm9000_interrupt
>dm9000_rx
>(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
||
dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
readsw(reg, data, (count+1) >> 1);
> skb = dev_alloc_skb(RxLen + 4)
> skb_reserve(skb, 2)
> rdptr = (u8 *) skb_put(skb, RxLen - 4)
> skb->protocol = eth_type_trans(skb, dev);
> netif_rx(skb);//向上报告,接收到的数据