现在的位置: 首页 > 综合 > 正文

dm9000驱动移植

2014年09月05日 ⁄ 综合 ⁄ 共 39796字 ⁄ 字号 评论关闭

 废话不说,直奔主题吧。

要想成功移植DM9000的驱动,首先应该了解Linux内核中platform驱动模型架构和网卡DM9000与cpu的硬件连接,

一、硬件链接情况

    DM9000在电路板上的连接中与编程相关的如下:
1)EECS拉高:16bit模式;
2)INT连接到2440 EINT18:INT脚为低时为有效中断信号,中断线为EINT18
3)cs连接到2440的nGCS4,CMD连接2440地址总线ADDR[2]:知道上面这些信息已经足够移植驱动了。

二、platform驱动模型

      从Linux 2.6起引入了一套新的驱动管理和注册机制:Platform_device和Platform_driver。Linux中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device表示,驱动用Platform_driver进行注册。

    Linux platform driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。

    Platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。通过Platform机制开发发底层驱动的大致流程为:  定义 platform_device à 注册 platform_device à 定义 platform_driver à注册 platform_driver。

    首先要确认的就是设备的资源信息,例如设备的地址,中断号等。

在2.6内核中platform设备用结构体platform_device来描述,该结构体定义在kernel/include/linux/platform_device.h中,

struct platform_device {

 const char * name;

 u32  id;

 struct device dev;

 u32  num_resources;

 struct resource * resource;

};

 

该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h中,

struct resource {

 const char *name;

 unsigned long start, end;

 unsigned long flags;

 struct resource *parent, *sibling, *child;

};

 

一个独立的挂接在cpu总线上的设备单元,一般都需要一段线性的地址空间来描述设备自身,linux是怎么管理所有的这些外部"物理地址范围段",进而给用户和linux自身一个比较好的观察4G总线上挂接的一个个设备实体的简洁、统一级联视图的呢?
    linux
采用struct resource结构体来描述一个挂接在cpu总线上的设备实体(32cpu的总线地址范围是0~4G):
resource->start
描述设备实体在cpu总线上的线性起始物理地址;
resource->end
-描述设备实体在cpu总线上的线性结尾物理地址;
resource->name
描述这个设备实体的名称,这个名字开发人员可以随意起,但最好贴切;
resource->flag
描述这个设备实体的一些共性和特性的标志位;

 

问题:我怎样知道设备实体在cpu总线上的线性起始物理地址跟线性结尾物理地址?

通过查看原理图吗??如果是,那具体应该怎样分析呢?

三、现在分析dm9000在Linux内核中的结构。

    static struct platform_device与static struct platform_resources结构体在arch/arm/plat-s3c24xx/devs.c中定义,在arch/arm/plat-s3c/include/plat/devs.h中声明,在arch/arm/mach-s3c2440/mach-smdk2440.c中使用(通过函数:platform_add_devices()注册进内核)。

至于platform_driver的实现就是在dm900.c中实现了。

四、移植

 

从上图可以看出

a. dm9000的访问地址为BANK4的基址(也许是通过上面的nGCS4看出来的)。(这个我是不明白的)
b. 只有一根地址线ADDR2。
c. 总线位宽为16位,有nWAIT信号。
d. 使用中断引脚为EINT18(使用LAN_INT实现的)。

一 增加DM9000平台设备
增加平台设备前首先要先定义该平台设备,这主要修改arch/arm/plat-s3c24xx/devs.c文件。
1.添加头文件 ,在devs.c文件的头文件引入处添加如下代码:

#include <linux/dm9000.h>

2.定义dm9000平台资源 ,在devs.c文件的合适处添加如下代码(其实看一下源文件就知道合适的意思):

 

  1. view plaincopy to clipboardprint?  
  2. ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150  
  3.  1. /* DM9000 */       
  4.  2. static struct resource s3c_dm9k_resource[] = {       
  5.  3.     [0] = {       
  6.  4.         .start = S3C2410_CS4,       
  7.  5.         .end   = S3C2410_CS4 + 3,       
  8.  6.         .flags = IORESOURCE_MEM,       
  9.  7.     },       
  10.  8.     [1] = {       
  11.  9.         .start = S3C2410_CS4 + 4,       
  12. 10.         .end   = S3C2410_CS4 + 4 + 3,       
  13. 11.         .flags = IORESOURCE_MEM,       
  14. 12.     },       
  15. 13.     [2] = {       
  16. 14.         .start = IRQ_EINT7,       
  17. 15.         .end   = IRQ_EINT7,       
  18. 16.         .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,       
  19. 17.     }       
  20. 18.        
  21. 19. };       
  22. 20.        
  23. 21. /* for the moment we limit ourselves to 16bit IO until some    
  24. 22.  * better IO routines can be written and tested    
  25. 23. */       
  26. 24.        
  27. 25. static struct dm9000_plat_data s3c_dm9k_platdata = {       
  28. 26.     .flags      = DM9000_PLATF_16BITONLY,       
  29. 27. };       
  30. 28.        
  31. 29. struct platform_device s3c_device_dm9k = {       
  32. 30.     .name       = "dm9000",       
  33. 31.     .id     = 0,       
  34. 32.     .num_resources  = ARRAY_SIZE(s3c_dm9k_resource),       
  35. 33.     .resource   = s3c_dm9k_resource,       
  36. 34.     .dev        = {       
  37. 35.         .platform_data = &s3c_dm9k_platdata,       
  38. 36.     }       
  39. 37. };       
  40. 38.        
  41. 39. EXPORT_SYMBOL(s3c_device_dm9k);      

 

 

  1. 1. /* DM9000 */    
  2.   2. static struct resource s3c_dm9k_resource[] = {    
  3.   3.     [0] = {    
  4.   4.         .start = S3C2410_CS4,    
  5.   5.         .end   = S3C2410_CS4 + 3,    
  6.   6.         .flags = IORESOURCE_MEM,    
  7.   7.     },    
  8.   8.     [1] = {    
  9.   9.         .start = S3C2410_CS4 + 4,    
  10.  10.         .end   = S3C2410_CS4 + 4 + 3,    
  11.  11.         .flags = IORESOURCE_MEM,    
  12.  12.     },    
  13.  13.     [2] = {    
  14.  14.         .start = IRQ_EINT7,    
  15.  15.         .end   = IRQ_EINT7,    
  16.  16.         .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,    
  17.  17.     }    
  18.  18.     
  19.  19. };    
  20.  20.     
  21.  21. /* for the moment we limit ourselves to 16bit IO until some  
  22.  22.  * better IO routines can be written and tested  
  23.  23. */    
  24.  24.     
  25.  25. static struct dm9000_plat_data s3c_dm9k_platdata = {    
  26.  26.     .flags      = DM9000_PLATF_16BITONLY,    
  27.  27. };    
  28.  28.     
  29.  29. struct platform_device s3c_device_dm9k = {    
  30.  30.     .name       = "dm9000",    
  31.  31.     .id     = 0,    
  32.  32.     .num_resources  = ARRAY_SIZE(s3c_dm9k_resource),    
  33.  33.     .resource   = s3c_dm9k_resource,    
  34.  34.     .dev        = {    
  35.  35.         .platform_data = &s3c_dm9k_platdata,    
  36.  36.     }    
  37.  37. };    
  38.  38.     
  39.  39. EXPORT_SYMBOL(s3c_device_dm9k);     

   

 

NOTE:
a.s3c_dm9k_resource数组定义了3个资源:两个内存空间和一个中断号。数组项0、1定义了访问dm9000时使用的地址。在dm9000的芯片手册上有如下的介绍:

    CMD Command Type
         When high, the access of this command cycle is DATA port
         When low, the access of this command cycle is ADDRESS port

所以数组项0、1的.start域就容易理解了,S3C2410_CS4中addr2为0,表示传输地址;S3C2410_CS4 + 4中addr2为1,表示传输数据。数组项[2]定义的中断号就较容易理解。
b.结构s3c_dm9k_platdata中指定了数据总线宽度为16。
c.结构s3c_device_dm9k就是dm9000的平台设备,其中.resource和.dev项分别指向前面定义的s3c_dm9k_resource和s3c_dm9k_platdata。

3.把定义的平台设备加入到内核设备列表中 ,在common-smdk.c文件的smdk_devs数组中添加一下代码:(我的为mach-mini2440.c文件mini2440_devices数组)

&s3c_device_dm9k,

这样,系统启动时就会把这个数组中的设备注册到内核中。

二 修改dm9000.c文件
对dm9000的枚举最终由dm9000_probe函数来实现。
1.添加头文件 ,在dm9000.c的头文件引入处增加以下代码,定义了一些寄存器的宏定义:

view plain copy to clipboard print ?
#if defined(CONFIG_ARCH_S3C2410)   
#include <mach/regs-mem.h>   
#endif   

view plaincopy to clipboardprint?
#if defined(CONFIG_ARCH_S3C2410)  
#include <mach/regs-mem.h>  
#endif 
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
 

2.修改probe函数 ,通过设置存储控制器使BANK4可用,修改后的dm9000_probe函数如下,其中修改的地方都由CONFIG_ARCH_S3C2410包括:

 

  1. view plaincopy to clipboardprint?  
  2. # *      
  3. #  * Search DM9000 board, allocate space and register it      
  4. #  */       
  5. # static int __devinit       
  6. # dm9000_probe(struct platform_device *pdev)       
  7. # {       
  8. #     struct dm9000_plat_data *pdata = pdev->dev.platform_data;       
  9. #     struct board_info *db;  /* Point a board information structure */       
  10. #     struct net_device *ndev;       
  11. #     const unsigned char *mac_src;       
  12. #     int ret = 0;       
  13. #     int iosize;       
  14. #     int i;       
  15. #     u32 id_val;       
  16. #        
  17. # #   if defined(CONFIG_ARCH_S3C2410)       
  18. #     unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;       
  19. #     unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;       
  20. # #   endif       
  21. #        
  22. #     /* Init network device */       
  23. #     ndev = alloc_etherdev(sizeof(struct board_info));       
  24. #     if (!ndev) {       
  25. #         dev_err(&pdev->dev, "could not allocate device./n");       
  26. #         return -ENOMEM;       
  27. #     }       
  28. #        
  29. #     SET_NETDEV_DEV(ndev, &pdev->dev);       
  30. #        
  31. #     dev_dbg(&pdev->dev, "dm9000_probe()/n");       
  32. #        
  33. # #if defined(CONFIG_ARCH_S3C2410)       
  34. #     *((volatile unsigned int *)S3C2410_BWSCON) =       
  35. #             (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;       
  36. #     *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;       
  37. # #endif       
  38. #        
  39. #     /* setup board info structure */       
  40. #     db = netdev_priv(ndev);       
  41. #     memset(db, 0, sizeof(*db));       
  42. #        
  43. #     db->dev = &pdev->dev;       
  44. #     db->ndev = ndev;       
  45. #        
  46. #     spin_lock_init(&db->lock);       
  47. #     mutex_init(&db->addr_lock);       
  48. #        
  49. #     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);       
  50. #        
  51. #     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);       
  52. #     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);       
  53. #     db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);       
  54. #        
  55. #     if (db->addr_res == NULL || db->data_res == NULL ||       
  56. #         db->irq_res == NULL) {       
  57. #         dev_err(db->dev, "insufficient resources/n");       
  58. #         ret = -ENOENT;       
  59. #         goto out;       
  60. #     }       
  61. #        
  62. #     iosize = res_size(db->addr_res);       
  63. #     db->addr_req = request_mem_region(db->addr_res->start, iosize,       
  64. #                       pdev->name);       
  65. #        
  66. #     if (db->addr_req == NULL) {       
  67. #         dev_err(db->dev, "cannot claim address reg area/n");       
  68. #         ret = -EIO;       
  69. #         goto out;       
  70. #     }       
  71. #        
  72. #     db->io_addr = ioremap(db->addr_res->start, iosize);       
  73. #        
  74. #     if (db->io_addr == NULL) {       
  75. #         dev_err(db->dev, "failed to ioremap address reg/n");       
  76. #         ret = -EINVAL;       
  77. #         goto out;       
  78. #     }       
  79. #        
  80. #     iosize = res_size(db->data_res);       
  81. #     db->data_req = request_mem_region(db->data_res->start, iosize,       
  82. #                       pdev->name);       
  83. #        
  84. #     if (db->data_req == NULL) {       
  85. #         dev_err(db->dev, "cannot claim data reg area/n");       
  86. #         ret = -EIO;       
  87. #         goto out;       
  88. #     }       
  89. #        
  90. #     db->io_data = ioremap(db->data_res->start, iosize);       
  91. #        
  92. #     if (db->io_data == NULL) {       
  93. #         dev_err(db->dev, "failed to ioremap data reg/n");       
  94. #         ret = -EINVAL;       
  95. #         goto out;       
  96. #     }       
  97. #        
  98. #     /* fill in parameters for net-dev structure */       
  99. #     ndev->base_addr = (unsigned long)db->io_addr;       
  100. #     ndev->irq    = db->irq_res->start;       
  101. #        
  102. #     /* ensure at least we have a default set of IO routines */       
  103. #     dm9000_set_io(db, iosize);       
  104. #        
  105. #     /* check to see if anything is being over-ridden */       
  106. #     if (pdata != NULL) {       
  107. #         /* check to see if the driver wants to over-ride the      
  108. #          * default IO width */       
  109. #        
  110. #         if (pdata->flags & DM9000_PLATF_8BITONLY)       
  111. #             dm9000_set_io(db, 1);       
  112. #        
  113. #         if (pdata->flags & DM9000_PLATF_16BITONLY)       
  114. #             dm9000_set_io(db, 2);       
  115. #        
  116. #         if (pdata->flags & DM9000_PLATF_32BITONLY)       
  117. #             dm9000_set_io(db, 4);       
  118. #        
  119. #         /* check to see if there are any IO routine      
  120. #          * over-rides */       
  121. #        
  122. #         if (pdata->inblk != NULL)       
  123. #             db->inblk = pdata->inblk;       
  124. #        
  125. #         if (pdata->outblk != NULL)       
  126. #             db->outblk = pdata->outblk;       
  127. #        
  128. #         if (pdata->dumpblk != NULL)       
  129. #             db->dumpblk = pdata->dumpblk;       
  130. #        
  131. #         db->flags = pdata->flags;       
  132. #     }       
  133. #        
  134. # #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL       
  135. #     db->flags |= DM9000_PLATF_SIMPLE_PHY;       
  136. # #endif       
  137. #        
  138. #     dm9000_reset(db);       
  139. #        
  140. #     /* try multiple times, DM9000 sometimes gets the read wrong */       
  141. #     for (i = 0; i < 8; i++) {       
  142. #         id_val  = ior(db, DM9000_VIDL);       
  143. #         id_val |= (u32)ior(db, DM9000_VIDH) << 8;       
  144. #         id_val |= (u32)ior(db, DM9000_PIDL) << 16;       
  145. #         id_val |= (u32)ior(db, DM9000_PIDH) << 24;       
  146. #        
  147. #         if (id_val == DM9000_ID)       
  148. #             break;       
  149. #         dev_err(db->dev, "read wrong id 0x%08x/n", id_val);       
  150. #     }       
  151. #        
  152. #     if (id_val != DM9000_ID) {       
  153. #         dev_err(db->dev, "wrong id: 0x%08x/n", id_val);       
  154. #         ret = -ENODEV;       
  155. #         goto out;       
  156. #     }       
  157. #        
  158. #     /* Identify what type of DM9000 we are working on */       
  159. #        
  160. #     id_val = ior(db, DM9000_CHIPR);       
  161. #     dev_dbg(db->dev, "dm9000 revision 0x%02x/n", id_val);       
  162. #        
  163. #     switch (id_val) {       
  164. #     case CHIPR_DM9000A:       
  165. #         db->type = TYPE_DM9000A;       
  166. #         break;       
  167. #     case CHIPR_DM9000B:       
  168. #         db->type = TYPE_DM9000B;       
  169. #         break;       
  170. #     default:       
  171. #         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E/n", id_val);       
  172. #         db->type = TYPE_DM9000E;       
  173. #     }       
  174. #        
  175. #     /* from this point we assume that we have found a DM9000 */       
  176. #        
  177. #     /* driver system function */       
  178. #     ether_setup(ndev);       
  179. #        
  180. #     ndev->open        = &dm9000_open;       
  181. #     ndev->hard_start_xmit    = &dm9000_start_xmit;       
  182. #     ndev->tx_timeout         = &dm9000_timeout;       
  183. #     ndev->watchdog_timeo = msecs_to_jiffies(watchdog);       
  184. #     ndev->stop        = &dm9000_stop;       
  185. #     ndev->set_multicast_list = &dm9000_hash_table;       
  186. #     ndev->ethtool_ops     = &dm9000_ethtool_ops;       
  187. #     ndev->do_ioctl        = &dm9000_ioctl;       
  188. #        
  189. # #ifdef CONFIG_NET_POLL_CONTROLLER       
  190. #     ndev->poll_controller     = &dm9000_poll_controller;       
  191. # #endif       
  192. #        
  193. #     db->msg_enable       = NETIF_MSG_LINK;       
  194. #     db->mii.phy_id_mask  = 0x1f;       
  195. #     db->mii.reg_num_mask = 0x1f;       
  196. #     db->mii.force_media  = 0;       
  197. #     db->mii.full_duplex  = 0;       
  198. #     db->mii.dev       = ndev;       
  199. #     db->mii.mdio_read    = dm9000_phy_read;       
  200. #     db->mii.mdio_write   = dm9000_phy_write;       
  201. #        
  202. # #if defined(CONFIG_ARCH_S3C2410)       
  203. #     printk("Now use the default MAC address: 08:90:90:90:90:90/n");       
  204. #     mac_src = "friendly-arm";       
  205. #     ndev->dev_addr[0] = 0x08;       
  206. #     ndev->dev_addr[1] = 0x90;       
  207. #     ndev->dev_addr[2] = 0x90;       
  208. #     ndev->dev_addr[3] = 0x90;       
  209. #     ndev->dev_addr[4] = 0x90;       
  210. #     ndev->dev_addr[5] = 0x90;       
  211. # #else       
  212. #     mac_src = "eeprom";       
  213. #        
  214. #     /* try reading the node address from the attached EEPROM */       
  215. #     for (i = 0; i < 6; i += 2)       
  216. #         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);       
  217. #        
  218. #     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {       
  219. #         mac_src = "platform data";       
  220. #         memcpy(ndev->dev_addr, pdata->dev_addr, 6);       
  221. #     }       
  222. #        
  223. #     if (!is_valid_ether_addr(ndev->dev_addr)) {       
  224. #         /* try reading from mac */       
  225. #                
  226. #         mac_src = "chip";       
  227. #         for (i = 0; i < 6; i++)       
  228. #             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);       
  229. #     }       
  230. #        
  231. #     if (!is_valid_ether_addr(ndev->dev_addr))       
  232. #         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "       
  233. #              "set using ifconfig/n", ndev->name);       
  234. # #endif       
  235. #        
  236. #     platform_set_drvdata(pdev, ndev);       
  237. #     ret = register_netdev(ndev);       
  238. #        
  239. #     if (ret == 0)       
  240. #         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)/n",       
  241. #                ndev->name, dm9000_type_to_char(db->type),       
  242. #                db->io_addr, db->io_data, ndev->irq,       
  243. #                ndev->dev_addr, mac_src);       
  244. #     return 0;       
  245. #        
  246. # out:       
  247. # #if defined(CONFIG_ARCH_S3C2410)       
  248. #     *(volatile unsigned int *)S3C2410_BWSCON   = oldval_bwscon;       
  249. #     *(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;       
  250. # #endif       
  251. #     dev_err(db->dev, "not found (%d)./n", ret);       
  252. #        
  253. #     dm9000_release_board(pdev, db);       
  254. #     free_netdev(ndev);       
  255. #        
  256. #     return ret;       
  257. # }      
  258. # *   
  259. #  * Search DM9000 board, allocate space and register it   
  260. #  */    
  261. # static int __devinit    
  262. # dm9000_probe(struct platform_device *pdev)    
  263. # {    
  264. #     struct dm9000_plat_data *pdata = pdev->dev.platform_data;    
  265. #     struct board_info *db;  /* Point a board information structure */    
  266. #     struct net_device *ndev;    
  267. #     const unsigned char *mac_src;    
  268. #     int ret = 0;    
  269. #     int iosize;    
  270. #     int i;    
  271. #     u32 id_val;    
  272. #     
  273. # #   if defined(CONFIG_ARCH_S3C2410)    
  274. #     unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;    
  275. #     unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;    
  276. # #   endif    
  277. #     
  278. #     /* Init network device */    
  279. #     ndev = alloc_etherdev(sizeof(struct board_info));    
  280. #     if (!ndev) {    
  281. #         dev_err(&pdev->dev, "could not allocate device./n");    
  282. #         return -ENOMEM;    
  283. #     }    
  284. #     
  285. #     SET_NETDEV_DEV(ndev, &pdev->dev);    
  286. #     
  287. #     dev_dbg(&pdev->dev, "dm9000_probe()/n");    
  288. #     
  289. # #if defined(CONFIG_ARCH_S3C2410)    
  290. #     *((volatile unsigned int *)S3C2410_BWSCON) =    
  291. #             (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;    
  292. #     *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;    
  293. # #endif    
  294. #     
  295. #     /* setup board info structure */    
  296. #     db = netdev_priv(ndev);    
  297. #     memset(db, 0, sizeof(*db));    
  298. #     
  299. #     db->dev = &pdev->dev;    
  300. #     db->ndev = ndev;    
  301. #     
  302. #     spin_lock_init(&db->lock);    
  303. #     mutex_init(&db->addr_lock);    
  304. #     
  305. #     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);    
  306. #     
  307. #     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);    
  308. #     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);    
  309. #     db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);    
  310. #     
  311. #     if (db->addr_res == NULL || db->data_res == NULL ||    
  312. #         db->irq_res == NULL) {    
  313. #         dev_err(db->dev, "insufficient resources/n");    
  314. #         ret = -ENOENT;    
  315. #         goto out;    
  316. #     }    
  317. #     
  318. #     iosize = res_size(db->addr_res);    
  319. #     db->addr_req = request_mem_region(db->addr_res->start, iosize,    
  320. #                       pdev->name);    
  321. #     
  322. #     if (db->addr_req == NULL) {    
  323. #         dev_err(db->dev, "cannot claim address reg area/n");    
  324. #         ret = -EIO;    
  325. #         goto out;    
  326. #     }    
  327. #     
  328. #     db->io_addr = ioremap(db->addr_res->start, iosize);    
  329. #     
  330. #     if (db->io_addr == NULL) {    
  331. #         dev_err(db->dev, "failed to ioremap address reg/n");    
  332. #         ret = -EINVAL;    
  333. #         goto out;    
  334. #     }    
  335. #     
  336. #     iosize = res_size(db->data_res);    
  337. #     db->data_req = request_mem_region(db->data_res->start, iosize,    
  338. #                       pdev->name);    
  339. #     
  340. #     if (db->data_req == NULL) {    
  341. #         dev_err(db->dev, "cannot claim data reg area/n");    
  342. #         ret = -EIO;    
  343. #         goto out;    
  344. #     }    
  345. #     
  346. #     db->io_data = ioremap(db->data_res->start, iosize);    
  347. #     
  348. #     if (db->io_data == NULL) {    
  349. #         dev_err(db->dev, "failed to ioremap data reg/n");    
  350. #         ret = -EINVAL;    
  351. #         goto out;    
  352. #     }    
  353. #     
  354. #     /* fill in parameters for net-dev structure */    
  355. #     ndev->base_addr = (unsigned long)db->io_addr;    
  356. #     ndev->irq    = db->irq_res->start;    
  357. #     
  358. #     /* ensure at least we have a default set of IO routines */    
  359. #     dm9000_set_io(db, iosize);    
  360. #     
  361. #     /* check to see if anything is being over-ridden */    
  362. #     if (pdata != NULL) {    
  363. #         /* check to see if the driver wants to over-ride the   
  364. #          * default IO width */    
  365. #     
  366. #         if (pdata->flags & DM9000_PLATF_8BITONLY)    
  367. #             dm9000_set_io(db, 1);    
  368. #     
  369. #         if (pdata->flags & DM9000_PLATF_16BITONLY)    
  370. #             dm9000_set_io(db, 2);    
  371. #     
  372. #         if (pdata->flags & DM9000_PLATF_32BITONLY)    
  373. #             dm9000_set_io(db, 4);    
  374. #     
  375. #         /* check to see if there are any IO routine   
  376. #          * over-rides */    
  377. #     
  378. #         if (pdata->inblk != NULL)    
  379. #             db->inblk = pdata->inblk;    
  380. #     
  381. #         if (pdata->outblk != NULL)    
  382. #             db->outblk = pdata->outblk;    
  383. #     
  384. #         if (pdata->dumpblk != NULL)    
  385. #             db->dumpblk = pdata->dumpblk;    
  386. #     
  387. #         db->flags = pdata->flags;    
  388. #     }    
  389. #     
  390. # #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL    
  391. #     db->flags |= DM9000_PLATF_SIMPLE_PHY;    
  392. # #endif    
  393. #     
  394. #     dm9000_reset(db);    
  395. #     
  396. #     /* try multiple times, DM9000 sometimes gets the read wrong */    
  397. #     for (i = 0; i < 8; i++) {    
  398. #         id_val  = ior(db, DM9000_VIDL);    
  399. #         id_val |= (u32)ior(db, DM9000_VIDH) << 8;    
  400. #         id_val |= (u32)ior(db, DM9000_PIDL) << 16;    
  401. #         id_val |= (u32)ior(db, DM9000_PIDH) << 24;    
  402. #     
  403. #         if (id_val == DM9000_ID)    
  404. #             break;    
  405. #         dev_err(db->dev, "read wrong id 0x%08x/n", id_val);    
  406. #     }    
  407. #     
  408. #     if (id_val != DM9000_ID) {    
  409. #         dev_err(db->dev, "wrong id: 0x%08x/n", id_val);    
  410. #         ret = -ENODEV;    
  411. #         goto out;    
  412. #     }    
  413. #     
  414. #     /* Identify what type of DM9000 we are working on */    
  415. #     
  416. #     id_val = ior(db, DM9000_CHIPR);    
  417. #     dev_dbg(db->dev, "dm9000 revision 0x%02x/n", id_val);    
  418. #     
  419. #     switch (id_val) {    
  420. #     case CHIPR_DM9000A:    
  421. #         db->type = TYPE_DM9000A;    
  422. #         break;    
  423. #     case CHIPR_DM9000B:    
  424. #         db->type = TYPE_DM9000B;    
  425. #         break;    
  426. #     default:    
  427. #         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E/n", id_val);    
  428. #         db->type = TYPE_DM9000E;    
  429. #     }    
  430. #     
  431. #     /* from this point we assume that we have found a DM9000 */    
  432. #     
  433. #     /* driver system function */    
  434. #     ether_setup(ndev);    
  435. #     
  436. #     ndev->open        = &dm9000_open;    
  437. #     ndev->hard_start_xmit    = &dm9000_start_xmit;    
  438. #     ndev->tx_timeout         = &dm9000_timeout;    
  439. #     ndev->watchdog_timeo = msecs_to_jiffies(watchdog);    
  440. #     ndev->stop        = &dm9000_stop;    
  441. #     ndev->set_multicast_list = &dm9000_hash_table;    
  442. #     ndev->ethtool_ops     = &dm9000_ethtool_ops;    
  443. #     ndev->do_ioctl        = &dm9000_ioctl;    
  444. #     
  445. # #ifdef CONFIG_NET_POLL_CONTROLLER    
  446. #     ndev->poll_controller     = &dm9000_poll_controller;    
  447. # #endif    
  448. #     
  449. #     db->msg_enable       = NETIF_MSG_LINK;    
  450. #     db->mii.phy_id_mask  = 0x1f;    
  451. #     db->mii.reg_num_mask = 0x1f;    
  452. #     db->mii.force_media  = 0;    
  453. #     db->mii.full_duplex  = 0;    
  454. #     db->mii.dev       = ndev;    
  455. #     db->mii.mdio_read    = dm9000_phy_read;    
  456. #     db->mii.mdio_write   = dm9000_phy_write;    
  457. #     
  458. # #if defined(CONFIG_ARCH_S3C2410)    
  459. #     printk("Now use the default MAC address: 08:90:90:90:90:90/n");    
  460. #     mac_src = "friendly-arm";    
  461. #     ndev->dev_addr[0] = 0x08;    
  462. #     ndev->dev_addr[1] = 0x90;    
  463. #     ndev->dev_addr[2] = 0x90;    
  464. #     ndev->dev_addr[3] = 0x90;    
  465. #     ndev->dev_addr[4] = 0x90;    
  466. #     ndev->dev_addr[5] = 0x90;    
  467. # #else    
  468. #     mac_src = "eeprom";    
  469. #     
  470. #     /* try reading the node address from the attached EEPROM */    
  471. #     for (i = 0; i < 6; i += 2)    
  472. #         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);    
  473. #     
  474. #     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {    
  475. #         mac_src = "platform data";    
  476. #         memcpy(ndev->dev_addr, pdata->dev_addr, 6);    
  477. #     }    
  478. #     
  479. #     if (!is_valid_ether_addr(ndev->dev_addr)) {    
  480. #         /* try reading from mac */    
  481. #             
  482. #         mac_src = "chip";    
  483. #         for (i = 0; i < 6; i++)    
  484. #             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);    
  485. #     }    
  486. #     
  487. #     if (!is_valid_ether_addr(ndev->dev_addr))    
  488. #         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "    
  489. #              "set using ifconfig/n", ndev->name);    
  490. # #endif    
  491. #     
  492. #     platform_set_drvdata(pdev, ndev);    
  493. #     ret = register_netdev(ndev);    
  494. #     
  495. #     if (ret == 0)    
  496. #         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)/n",    
  497. #                ndev->name, dm9000_type_to_char(db->type),    
  498. #                db->io_addr, db->io_data, ndev->irq,    
  499. #                ndev->dev_addr, mac_src);    
  500. #     return 0;    
  501. #     
  502. # out:    
  503. # #if defined(CONFIG_ARCH_S3C2410)    
  504. #     *(volatile unsigned int *)S3C2410_BWSCON   = oldval_bwscon;    
  505. #     *(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;    
  506. # #endif    
  507. #     dev_err(db->dev, "not found (%d)./n", ret);    
  508. #     
  509. #     dm9000_release_board(pdev, db);    
  510. #     free_netdev(ndev);    
  511. #     
  512. #     return ret;    
  513. # }     

 

a.第24-27行定义了两个变量,用来保存BWSCON和BANKCON4的值,下面将会用到。

b.第32-39对BANK4进行了设置。首先设置BWSCON,

9对BANK4进行了设置。首先设置BWSCON,

view plain copy to clipboard print ?

  1. #if defined(CONFIG_ARCH_S3C2410)      
  2.     *((volatile  unsigned  int  *)S3C2410_BWSCON) =     
  3.             (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;     
  4.     *((volatile  unsigned  int  *)S3C2410_BANKCON4) = 0x1f7c;     
  5. #endif      
  6. view plaincopy to clipboardprint?  
  7. #if defined(CONFIG_ARCH_S3C2410)     
  8.     *((volatile unsigned int *)S3C2410_BWSCON) =     
  9.             (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;     
  10.     *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;     
  11. #endif    
  12. #if defined(CONFIG_ARCH_S3C2410)  
  13.  *((volatile unsigned int *)S3C2410_BWSCON) =  
  14.    (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;  
  15.  *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;  
  16. #endif      

 

主要是设置了总线宽度16,nWAIT,ST。(具体的可以参考s3c2440数据手册的BUS WIDTH & WAIT CONTROL REGISTER (BWSCON))。然后设置BANKCON4的时间参数,值为0×1f7c(pmc:normal Tacp:6clk Tcah:4clk Tcoh:1clk Tacc:14clk Tcos:4clk 具体可以参考s3c2440数据手册的BANK CONTROL REGISTER)

c.第209-216的代码是我自己给注释的,据其意思,上面首先给MAC赋值,然后检测合法性,但经实践,判断语句总成立,所以在linux启动注册dm9000时总输出Invalid ethernet MAC address.反正后面也会再次给MAC地址赋值,所以干脆把这几行代码注释掉。

d.第218-227行就是给MAC地址赋值的,听说赋什么值都可以,有这么神奇吗?

e.第266-269行恢复寄存器原来的值。

f.以上的步骤和代码都是参考书上的,但可惜的是,按照上面步骤去修改,系统能成功加载dm9000驱动,但无法ping通,这个事确实让我很苦恼,上网找了很多资料,最后发现大多数都需要调用writel来设置BWSCON、GPFCON和中断等。所以无计之下参考了mini2440中的一段代码,出自附送光盘的无操作系统代码测试的dm9000部分。

到此 ,代码的移植到此为止,然后是配置内核,以使用dm9000。在

-> Device Drivers                                                   
        --> Network device support                                       
           --> Network device support (NETDEVICES [=y])                      
             --> Ethernet (10 or 100Mbit) 处将DM9000网卡选为编译进内核。
然后在/etc/init.d/rcS文件的开始处加入

ifconfig
 eth0 192.168.1.22<
pre>
当然,ip地址是因人而定的,尽量设为和PC在同一个网段。重新将内核下载到开发板后启动

 

抱歉!评论已关闭.