typedef struct board_info {
void __iomem *io_addr; /* Register I/O base address *///虚拟的通过IO映射的
void __iomem *io_data; /* Data I/O address */
u16 irq; /* IRQ */
/**********************************都通过映射后的**********************************************************************************************************/
u16 tx_pkt_cnt;
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;
unsigned int wake_supported :1;
int debug_level;
enum dm9000_type type;
//IO模式
void (*inblk)(void __iomem *port, void *data, int length);
void (*outblk)(void __iomem *port, void *data, int length);
void (*dumpblk)(void __iomem *port, int length);
struct device *dev; /* parent device */
//平台设备资源
struct resource *addr_res; /* 地址资源resources found */
struct resource *data_res; /**IO数据资源**/
struct resource *addr_req; /* 分配后的地址内存资源*/
struct resource *data_req; /* 分配后的数据资源*/
struct resource *irq_res; /**中断资源***/
int irq_wake;
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;
u32 wake_state;
int rx_csum;
int can_csum;
int ip_summed;
} board_info_t;
/**************************************************************************************************************************************************************/
2.1、 注册平台驱动。
将驱动添加到总线上,完成驱动和设备的匹配,并执行驱动的probe函数。
static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
.pm = &dm9000_drv_pm_ops,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
};
static int __init dm9000_init(void)
{
printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);
return platform_driver_register(&dm9000_driver);
}
2.2、dm9000_probe探测函数的分析
static int __devinit dm9000_probe(struct platform_device *pdev)
{
//定义局部变量用来保存数据
struct dm9000_plat_data *pdata = pdev->dev.platform_data;
struct board_info *db; /* Point a board information structure */
struct net_device *ndev;
const unsigned char *mac_src;
int ret = 0;
int iosize;
int i;
u32 id_val;
/**内核用net_device结构来描述一个网络设备并使用alloc_etherdev或者alloc_netdev函数来分配一个net_device结构
/* Init network device */
ndev = alloc_etherdev(sizeof(struct board_info));
if (!ndev) {
dev_err(&pdev->dev, "could not allocate device.\n");
return -ENOMEM;
}
//platform_device与net_device关联起来
SET_NETDEV_DEV(ndev, &pdev->dev);//通过这一步网络设备和平台设备即关联起来了
dev_dbg(&pdev->dev, "dm9000_probe()\n");
/* setup board info structure */
db = netdev_priv(ndev);/**获取net_device结构的私有成员保存到struct board_info *db中**/
db->dev = &pdev->dev;
db->ndev = ndev;
spin_lock_init(&db->lock);/**初始化自旋锁**/
mutex_init(&db->addr_lock);
//初始化延迟等待队列并传入dm9000_poll_work该函数将在设备被打开的时候被调度
INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
//获取平台资源?从哪里获取?
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//dm9k平台设备所所使用的IO地址资源
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);//dm9k平台设备所所使用的IO数据资源
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //dm9k平台设备所所使用中断资源
if (db->addr_res == NULL || db->data_res == NULL ||
db->irq_res == NULL) {
dev_err(db->dev, "insufficient resources\n");
ret = -ENOENT;
goto out;
}
//获取dm9k平台设备所使用的中断号
db->irq_wake = platform_get_irq(pdev, 1);
if (db->irq_wake >= 0) {
dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
//申请中断
ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
IRQF_SHARED, dev_name(db->dev), ndev);
if (ret) {
dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
} else {
/* test to see if irq is really wakeup capable */
ret = irq_set_irq_wake(db->irq_wake, 1);
if (ret) {
dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
db->irq_wake, ret);
ret = 0;
} else {
irq_set_irq_wake(db->irq_wake, 0);
db->wake_supported = 1;
}
}
}
/*计算上面所获取到的IO地址平台资源的大小*/
iosize = resource_size(db->addr_res);
//为IO地址空间分配IO内存
db->addr_req = request_mem_region(db->addr_res->start, iosize,
pdev->name);//物理
if (db->addr_req == NULL) {
dev_err(db->dev, "cannot claim address reg area\n");
ret = -EIO;
goto out;
}
//在访问IO内存之前必须映射IO内存
db->io_addr = ioremap(db->addr_res->start, iosize);//虚拟地址
if (db->io_addr == NULL) {
dev_err(db->dev, "failed to ioremap address reg\n");
ret = -EINVAL;
goto out;
}
iosize = resource_size(db->data_res);
db->data_req = request_mem_region(db->data_res->start, iosize,
pdev->name);
if (db->data_req == NULL) {
dev_err(db->dev, "cannot claim data reg area\n");
ret = -EIO;
goto out;
}
db->io_data = ioremap(db->data_res->start, iosize);
if (db->io_data == NULL) {
dev_err(db->dev, "failed to ioremap data reg\n");
ret = -EINVAL;
goto out;
}
/* fill in parameters for net-dev structure */
ndev->base_addr = (unsigned long)db->io_addr;//初始化IO基地址
ndev->irq = db->irq_res->start; //初始化irq