s3c6410自带的DM9000网卡驱动也是基于platform设备模型。
其定义的设备资源在arch/arm/mach-s3c64xx/mach-smdk6410中。有网卡的resource resource dm9000_resources[],还有一些板级信息,dm9000_plat_data dm9000_setup。
1.宏及参数 //板级、系统定义
1 #define DM9000_PHY 0x40 /* PHY address 0x01 */
2
3 #define CARDNAME 'dm9000'
4 #define DRV_VERSION '1.31'
5 /*
6 * Transmit timeout, default 5 seconds.
7 */
8 static int watchdog = 5000; //5s的延时时间
9 module_param(watchdog, int, 0400);
10 MODULE_PARM_DESC(watchdog, 'transmit timeout in milliseconds');
11 enum dm9000_type { //开发板定义了三个DM9000类型
12 TYPE_DM9000E, /* original DM9000 */
13 TYPE_DM9000A,
14 TYPE_DM9000B
15 };
2.模块注册
此处因为基于platform模型,采用platform_driver_register函数注册内核模块,当设备驱动与设备匹配真确后,转入执行dm9000_probe()函数,该函数包含真正的dm9000网卡驱动注册函数是register_netdev()函数。
1 static int __init dm9000_init(void)
2 {
3 printk(KERN_INFO '%s Ethernet Driver, V%sn', CARDNAME, DRV_VERSION);
4
5 return platform_driver_register(&dm9000_driver); //platform设备模型注册驱动
6 }
dm9000的platform设备驱动函数如下:
1 static struct platform_driver dm9000_driver = {
2 .driver = {
3 .name = 'dm9000',
4 .owner = THIS_MODULE,
5 .pm = &dm9000_drv_pm_ops,
6 },
7 .probe = dm9000_probe,
8 .remove = __devexit_p(dm9000_drv_remove),
9 };
3.dm9000_probe函数
主要完成网络设备的初始化,以及网卡驱动的注册register_netdev()
1 static int __devinit dm9000_probe(struct platform_device *pdev)
2 {
3 struct dm9000_plat_data *pdata = pdev->dev.platform_data;//驱动程序中获得系统定义的网卡板级信息
4 //定义在/arch/arm/mach-s3c64xx/mach-smdk6410.c中。
5 struct board_info *db; /* Point a board information structure */
6 struct net_device *ndev; //定义设备结构体
7 const unsigned char *mac_src;
8 int ret = 0;
9 int iosize;
10 int i;
11 u32 id_val;
12
13 /* Init network device */
14 //分配生成net_device结构体 alloc_etherdev是alloc_netdev()针对以太网的快捷操作函数
15 ndev = alloc_etherdev(sizeof(struct board_info));
16
17 //判断是否分配正确
18 if (!ndev) {
19 dev_err(&pdev->dev, 'could not allocate device.n');
20 return -ENOMEM;
21 }
22 //建立net_device到device的连接
23 SET_NETDEV_DEV(ndev, &pdev->dev);
24 //内核输出信息
25 dev_dbg(&pdev->dev, 'dm9000_probe()n');
26 //函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。
27 /* setup board info structure */
28 db = netdev_priv(ndev);
29
30 db->dev = &pdev->dev;
31 db->ndev = ndev;
32
33 spin_lock_init(&db->lock);//初始化自旋锁
34 mutex_init(&db->addr_lock);
35
36 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //??
37 //获取平台设备资源 resource 地址空间、数据空间、中断信号 7号中断
38 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
39 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
40 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
41 //判断资源是否获取成功
42 if (db->addr_res == NULL || db->data_res == NULL ||
43 db->irq_res == NULL) {
44 dev_err(db->dev, 'insufficient resourcesn');
45 ret = -ENOENT;
46 goto out;
47 }
48 //platform_get_resource的变体 同 platform_get_resource(pdev, IORESOURCE_IRQ, 1)
49 db->irq_wake = platform_get_irq(pdev, 1);
50 if (db->irq_wake >= 0) {
51 dev_dbg(db->dev, 'wakeup irq %dn', db->irq_wake);
52 //前面获得中断号 申请中断
53 ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
54 IRQF_SHARED, dev_name(db->dev), ndev);
55 if (ret) {
56 dev_err(db->dev, 'cannot get wakeup irq (%d)n', ret);
57 } else {
58 /* test to see if irq is really wakeup capable */
59 ret = set_irq_wake(db->irq_wake, 1);
60 if (ret) {
61 dev_err(db->dev, 'irq %d cannot set wakeup (%d)n',
62 db->irq_wake, ret);
63 ret = 0;
64 } else {
65 set_irq_wake(db->irq_wake, 0);
66 db->wake_supported = 1;
67 }
68 }
69 }
70 //IO资源分配大小 地址 为resource分配内存
71 iosize = resource_size(db->addr_res);
72 db->addr_req = request_mem_region(db->addr_res->start, iosize,
73 pdev->name); //内存申请
74
75 if (db->addr_req == NULL) {
76 dev_err(db->dev, 'cannot claim address reg arean');
77 ret = -EIO;
78 goto out;
79 }
80
81 db->io_addr = ioremap(db->addr_res->start, iosize);
82
83 if (db->io_addr == NULL) {
84 dev_err(db->dev, 'failed to ioremap address regn');
85 ret = -EINVAL;
86 goto out;
87 }
88
89 iosize = resource_size(db->data_res);
90 db->data_req = request_mem_region(db->data_res->start, iosize,
91 pdev->name);
92
93 if (db->data_req == NULL) {
94 dev_err(db->dev, 'cannot claim data reg arean');
95 ret = -EIO;
96 goto out;
97 }
98
99 db->io_data = ioremap(db->data_res->start, iosize);
100
101 if (db->io_data == NULL) {
102 dev_err(db->dev, 'failed to ioremap data regn');
103 ret = -EINVAL;
104 goto out;
105 }
106 //初始化net_device中的成员
107 /* fill in parameters for net-dev structure */
108 ndev->base_addr = (unsigned long)db->io_addr; //网络接口的IO基地址
109 ndev->irq = db->irq_res->start;//中断号 ifconfig时会打印出这个值 也可通过这个修改
110
111 /* ensure at least we have a default set of IO routines */
112 dm9000_set_io(db, iosize);
113
114 /* check to see if anything is being over-ridden */
115 if (pdata != NULL) {
116 /* check to see if the driver wants to over-ride the
117 * default IO width */
118 //检测与板级信息是否相同
119 if (pdata->flags & DM9000_PLATF_8BITONLY)
120 dm9000_set_io(db, 1);
121
122 if (pdata->flags & DM9000_PLATF_16BITONLY)
123 dm9000_set_io(db, 2);
124
125 if (pdata->flags & DM9000_PLATF_32BITONLY)
126 dm9000_set_io(db, 4);
127
128 /* check to see if there are any IO routine
129 * over-rides */
130
131 if (pdata->inblk != NULL)
132 db->inblk = pdata->inblk;